#ifndef DSPNASM_REGISTER_H
#define DSPNASM_REGISTER_H

#include <string>
#include <algorithm>
#include "nasm/type/type.h"

namespace dspnasm {

    enum class RegKind {
        A0 = 0,
        A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15,
        A16, A17, A18, A19, A20, A21, A22, A23, A24, A25, A26, A27, A28, A29, A30, A31,
        B0, B1, B2, B3, B4, B5, B6, B7, B8, B9, B10, B11, B12, B13, B14, B15,
        B16, B17, B18, B19, B20, B21, B22, B23, B24, B25, B26, B27, B28, B29, B30, B31,
        AMR,    // Addressing mode register
        CSR,        // Control status register
        GFPGFR,     // Galois field multiply control register
        ICR,        // Interrupt clear register
        IER,        // Interrupt enable register
        IFR,        // Interrupt flag register
        IRP,        // Interrupt return pointer register
        ISR,        // Interrupt set register
        ISTP,       // Interrupt service table pointer register
        NRP,        // Nonmaskable interrupt return pointer register
        PCE1,       // Program counter, E1 phase
        /// Control Register File Extensions
        DNUM,       // DSP core number register
        ECR,        // Exception clear register
        EFR,        // Exception flag register
        GPLYA,      // GMPY A-side polynomial register
        GPLYB,      // GMPY B-side polynomial register
        IERR,       // Internal exception report register
        ILC,        // Inner loop count register
        ITSR,       // Interrupt task state register
        NTSR,       // NMI/Exception task state register
        REP,        // Restricted entry point address register
        RILC,       // Reload inner loop count register
        SSR,        // Saturation status register
        TSCH,       // Time-stamp counter (high 32) register
        TSCL,       // Time-stamp counter (low 32) register
        TSR,        // Task state register
        /// Control Register File Extensions for Floating-point Operations
        FADCR,      // Floating-point adder configuration register
        FAUCR,      // Floating-point auxiliary configuration register
        FMCR,       // Floating-point multiplier configuration register
        Num_Of_Reg,
        UN_KNOWN
    };

    static const char *RegName[] = {
            "A0", "A1", "A2", "A3",
            "A4", "A5", "A6", "A7",
            "A8", "A9", "A10", "A11",
            "A12", "A13", "A14", "A15",
            "A16", "A17", "A18", "A19",
            "A20", "A21", "A22", "A23",
            "A24", "A25", "A26", "A27",
            "A28", "A29", "A30", "A31",
            "B0", "B1", "B2", "B3",
            "B4", "B5", "B6", "B7",
            "B8", "B9", "B10", "B11",
            "B12", "B13", "B14", "B15",
            "B16", "B17", "B18", "B19",
            "B20", "B21", "B22", "B23",
            "B24", "B25", "B26", "B27",
            "B28", "B29", "B30", "B31",
            "AMR", "CSR", "GFPGFR", "ICR",
            "IER", "IFR", "IRP", "ISR",
            "ISTP", "NRP", "PCE1", "DNUM",
            "ECR", "EFR", "GPLYA", "GPLYB",
            "IERR", "ILC", "ITSR", "NTSR",
            "REP", "RILC", "SSR", "TSCH",
            "TSCL", "TSR", "FADCR", "FAUCR",
            "FMCR"
    };

    static RegKind getRegKind(std::string regName) {
        std::transform(regName.begin(), regName.end(), regName.begin(), ::toupper);
        for (u32 i = 0; i < static_cast<u32>(RegKind::Num_Of_Reg); ++i) {
            if (RegName[i] == regName) {
                return static_cast<RegKind>(i);
            }
        }
        return RegKind::UN_KNOWN;
    }

    static std::string getRegName(RegKind regKind) {
        if (regKind >= RegKind::Num_Of_Reg) {
            return {"UN_KNOWN"};
        }

        u32 regIndex = static_cast<u32>(regKind);
        return RegName[regIndex];
    }
}

#endif //DSPNASM_REGISTER_H
